package cn.stylefeng.roses.kernel.manage.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.stylefeng.roses.kernel.db.api.factory.PageFactory;
import cn.stylefeng.roses.kernel.db.api.factory.PageResultFactory;
import cn.stylefeng.roses.kernel.db.api.pojo.page.PageResult;
import cn.stylefeng.roses.kernel.manage.entity.ApiClientAuth;
import cn.stylefeng.roses.kernel.manage.entity.ApiEndpoint;
import cn.stylefeng.roses.kernel.manage.enums.ApiEndpointExceptionEnum;
import cn.stylefeng.roses.kernel.manage.mapper.ApiEndpointMapper;
import cn.stylefeng.roses.kernel.manage.pojo.request.ApiEndpointRequest;
import cn.stylefeng.roses.kernel.manage.service.ApiClientAuthService;
import cn.stylefeng.roses.kernel.manage.service.ApiEndpointService;
import cn.stylefeng.roses.kernel.rule.exception.base.ServiceException;
import cn.stylefeng.roses.kernel.sys.modular.resource.entity.SysResource;
import cn.stylefeng.roses.kernel.sys.modular.resource.service.SysResourceService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * API资源接口列表业务实现层
 *
 * @author fengshuonan
 * @since 2023/10/23 22:57
 */
@Service
public class ApiEndpointServiceImpl extends ServiceImpl<ApiEndpointMapper, ApiEndpoint> implements ApiEndpointService {

    @Resource
    private SysResourceService sysResourceService;

    @Resource
    private ApiClientAuthService apiClientAuthService;

    @Override
    public void add(ApiEndpointRequest apiEndpointRequest) {

        // 校验编码是否合法
        this.validateResourceRight(apiEndpointRequest.getResourceCode());

        ApiEndpoint apiEndpoint = new ApiEndpoint();
        BeanUtil.copyProperties(apiEndpointRequest, apiEndpoint);
        this.save(apiEndpoint);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void del(ApiEndpointRequest apiEndpointRequest) {
        ApiEndpoint apiEndpoint = this.queryApiEndpoint(apiEndpointRequest);
        this.removeById(apiEndpoint.getApiClientResourceId());

        // 删除这个资源的关联关系
        String resourceCode = apiEndpoint.getResourceCode();
        LambdaQueryWrapper<ApiClientAuth> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ApiClientAuth::getResourceCode, resourceCode);
        apiClientAuthService.remove(queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchDelete(ApiEndpointRequest apiEndpointRequest) {

        // 查询这些id对应的资源编码集合
        List<Long> apiClientResourceIdList = apiEndpointRequest.getApiClientResourceIdList();
        LambdaQueryWrapper<ApiEndpoint> apiEndpointLambdaQueryWrapper = new LambdaQueryWrapper<>();
        apiEndpointLambdaQueryWrapper.in(ApiEndpoint::getApiClientResourceId, apiClientResourceIdList);
        apiEndpointLambdaQueryWrapper.select(ApiEndpoint::getResourceCode);
        List<ApiEndpoint> apiEndpoints = this.list(apiEndpointLambdaQueryWrapper);

        if (ObjectUtil.isEmpty(apiEndpoints)) {
            return;
        }

        // 删除接口资源集合
        this.removeByIds(apiClientResourceIdList);

        // 根据资源编码集合，删除权限关联关系
        List<String> resourceCodeList = apiEndpoints.stream().map(ApiEndpoint::getResourceCode).collect(Collectors.toList());
        LambdaQueryWrapper<ApiClientAuth> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(ApiClientAuth::getResourceCode, resourceCodeList);
        apiClientAuthService.remove(queryWrapper);
    }

    @Override
    public void edit(ApiEndpointRequest apiEndpointRequest) {

        // 校验编码是否合法
        this.validateResourceRight(apiEndpointRequest.getResourceCode());

        ApiEndpoint apiEndpoint = this.queryApiEndpoint(apiEndpointRequest);
        BeanUtil.copyProperties(apiEndpointRequest, apiEndpoint);
        this.updateById(apiEndpoint);
    }

    @Override
    public ApiEndpoint detail(ApiEndpointRequest apiEndpointRequest) {
        ApiEndpoint apiEndpoint = this.queryApiEndpoint(apiEndpointRequest);

        // 通过编码获取资源的详细信息
        String resourceCode = apiEndpoint.getResourceCode();
        LambdaQueryWrapper<SysResource> sysResourceLambdaQueryWrapper = new LambdaQueryWrapper<>();
        sysResourceLambdaQueryWrapper.eq(SysResource::getResourceCode, resourceCode);
        SysResource sysResource = this.sysResourceService.getOne(sysResourceLambdaQueryWrapper, false);
        if (sysResource != null) {
            apiEndpoint.setResourceName(sysResource.getResourceName());
            apiEndpoint.setUrl(sysResource.getUrl());
            apiEndpoint.setHttpMethod(sysResource.getHttpMethod());
        }

        return apiEndpoint;
    }

    @Override
    public PageResult<ApiEndpoint> findPage(ApiEndpointRequest apiEndpointRequest) {

        // 根据请求的条件查询编码和请求路径是否匹配
        String searchText = apiEndpointRequest.getSearchText();
        List<String> conditionResCodeList = new ArrayList<>();
        if (ObjectUtil.isNotEmpty(searchText)) {

            // 查询资源表是否有该查询条件的资源
            LambdaQueryWrapper<SysResource> sysResourceLambdaQueryWrapper = new LambdaQueryWrapper<>();
            sysResourceLambdaQueryWrapper.like(SysResource::getResourceCode, searchText).or().like(SysResource::getUrl, searchText).or()
                    .like(SysResource::getResourceName, searchText);
            sysResourceLambdaQueryWrapper.select(SysResource::getResourceCode);
            List<SysResource> list = sysResourceService.list(sysResourceLambdaQueryWrapper);

            if (ObjectUtil.isNotEmpty(list)) {
                conditionResCodeList = list.stream().map(SysResource::getResourceCode).collect(Collectors.toList());
            }
        }

        // 根据res表的请求结果继续查询
        LambdaQueryWrapper<ApiEndpoint> apiEndpointLambdaQueryWrapper = new LambdaQueryWrapper<>();
        if (ObjectUtil.isNotEmpty(conditionResCodeList)) {
            apiEndpointLambdaQueryWrapper.in(ApiEndpoint::getResourceCode, conditionResCodeList);
        }
        Page<ApiEndpoint> pageList = this.page(PageFactory.defaultPage(), apiEndpointLambdaQueryWrapper);

        // 查询结果为空，直接返回
        List<ApiEndpoint> records = pageList.getRecords();
        if (ObjectUtil.isEmpty(records)) {
            return PageResultFactory.createPageResult(pageList);
        }

        // 补充列表需要的信息
        this.fillSysResourceInfo(records);

        return PageResultFactory.createPageResult(pageList);
    }

    @Override
    public List<ApiEndpoint> getUrlSelectList(ApiEndpointRequest apiEndpointRequest) {

        // url搜索条件
        String searchText = apiEndpointRequest.getSearchText();

        // 查询资源列表
        LambdaQueryWrapper<SysResource> sysResourceLambdaQueryWrapper = new LambdaQueryWrapper<>();
        if (ObjectUtil.isNotEmpty(searchText)) {
            sysResourceLambdaQueryWrapper.like(SysResource::getUrl, searchText);
            sysResourceLambdaQueryWrapper.select(SysResource::getUrl, SysResource::getResourceName, SysResource::getResourceCode,
                    SysResource::getHttpMethod);
            List<SysResource> sysResourceList = this.sysResourceService.list(sysResourceLambdaQueryWrapper);
            if (ObjectUtil.isEmpty(sysResourceList)) {
                return new ArrayList<>();
            }
            return BeanUtil.copyToList(sysResourceList, ApiEndpoint.class);
        }

        // 如果不带参数，则只查询分页查询20条，否则会显示出很多资源
        else {
            Page<SysResource> page = this.sysResourceService.page(PageFactory.defaultPage(), sysResourceLambdaQueryWrapper);
            List<SysResource> records = page.getRecords();
            if (ObjectUtil.isEmpty(records)) {
                return new ArrayList<>();
            }
            return BeanUtil.copyToList(records, ApiEndpoint.class);
        }
    }

    @Override
    public List<ApiEndpoint> getTotalEndpoint() {
        List<ApiEndpoint> apiEndpoints = getTotalApiEndPoint();
        if (ObjectUtil.isEmpty(apiEndpoints)) {
            return new ArrayList<>();
        }

        // 补充列表需要的信息
        this.fillSysResourceInfo(apiEndpoints);

        return apiEndpoints;
    }

    @Override
    public List<String> getTotalEndpointCodeList() {
        List<ApiEndpoint> apiEndpoints = getTotalApiEndPoint();
        if (ObjectUtil.isEmpty(apiEndpoints)) {
            return new ArrayList<>();
        }

        return apiEndpoints.stream().map(ApiEndpoint::getResourceCode).collect(Collectors.toList());
    }

    /**
     * 获取信息
     *
     * @author fengshuonan
     * @since 2023/10/23 22:57
     */
    private ApiEndpoint queryApiEndpoint(ApiEndpointRequest apiEndpointRequest) {
        ApiEndpoint apiEndpoint = this.getById(apiEndpointRequest.getApiClientResourceId());
        if (ObjectUtil.isEmpty(apiEndpoint)) {
            throw new ServiceException(ApiEndpointExceptionEnum.API_ENDPOINT_NOT_EXISTED);
        }
        return apiEndpoint;
    }

    /**
     * 补充列表需要的资源详情信息
     *
     * @author fengshuonan
     * @since 2023/10/25 16:05
     */
    private void fillSysResourceInfo(List<ApiEndpoint> records) {
        // 补充列表需要的信息
        List<String> resourceCodeList = records.stream().map(ApiEndpoint::getResourceCode).collect(Collectors.toList());
        LambdaQueryWrapper<SysResource> resWrapper = new LambdaQueryWrapper<>();
        resWrapper.in(SysResource::getResourceCode, resourceCodeList);
        resWrapper.select(SysResource::getResourceName, SysResource::getResourceCode, SysResource::getUrl, SysResource::getHttpMethod);
        List<SysResource> sysResourceList = this.sysResourceService.list(resWrapper);
        for (ApiEndpoint record : records) {
            for (SysResource sysResource : sysResourceList) {
                if (record.getResourceCode().equals(sysResource.getResourceCode())) {
                    record.setResourceName(sysResource.getResourceName());
                    record.setUrl(sysResource.getUrl());
                    record.setHttpMethod(sysResource.getHttpMethod());
                }
            }
        }
    }

    /**
     * 获取所有的api应用资源
     *
     * @author fengshuonan
     * @since 2023/10/25 18:25
     */
    private List<ApiEndpoint> getTotalApiEndPoint() {
        LambdaQueryWrapper<ApiEndpoint> apiEndpointLambdaQueryWrapper = new LambdaQueryWrapper<>();
        apiEndpointLambdaQueryWrapper.select(ApiEndpoint::getApiClientResourceId, ApiEndpoint::getResourceCode);
        return this.list(apiEndpointLambdaQueryWrapper);
    }

    /**
     * 校验资源编码是否合法
     *
     * @author fengshuonan
     * @since 2023/10/25 20:36
     */
    private void validateResourceRight(String resourceCode) {
        LambdaQueryWrapper<SysResource> sysResourceLambdaQueryWrapper = new LambdaQueryWrapper<>();
        sysResourceLambdaQueryWrapper.eq(SysResource::getResourceCode, resourceCode);
        long count = this.sysResourceService.count(sysResourceLambdaQueryWrapper);
        if (count == 0) {
            throw new ServiceException(ApiEndpointExceptionEnum.API_ENDPOINT_NOT_RIGHT);
        }
    }

}
